package com.newly.common.core.utils.file;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.newly.common.base.exception.FileClientException;
import org.springframework.web.multipart.MultipartFile;

import java.io.*;
import java.util.Properties;

/**
 * @program: file-client
 * @remark: 文件客户端基类
 * @author: guan
 * @create: 2021-11-05 14:37
 */
public class AbstractFileClient {
    /**
     * 类路劲下的配置文件，必须将配置文件放置配置文件中
     */
    protected static final String CLASSPATH_CONFIG_FILENAME = "fileConfig.properties";

    /**
     * 文件环境，根据环境来判断是使用本地环境或服务环境
     * 本地环境：返回的真实路径是（c:/a）格式路劲
     * 服务环境：通过应用服务器代理的文件（192.168.1.211:8989/res）
     */
    protected FileEnv fileEnv;

    /**
     * 服务器主机地址
     */
    protected String serverHost;

    /**
     * 服务器端口
     */
    protected int serverPort;

    /**
     * 服务资源访问根路劲
     */
    protected String serverUriPath;

    /**
     * 上传文件后的磁盘路劲
     */
    protected String serverDiskPath;

    /**
     * local 根路劲
     */
    protected String localRootPath;

    /**
     * ftp ip
     */
    protected String ftpId;

    /**
     * ftp端口
     */
    protected int ftpPort;

    /**
     * ftp用户名
     */
    protected String ftpUsername;

    /**
     * ftp密码
     */
    protected String ftpPassword;

    /**
     * ftp根路劲
     */
    protected String ftpRootPath;


    public AbstractFileClient() {
        this.initProp();
    }

    /**
     * 读取配置文件，初始化属性
     */
    protected void initProp() {
        InputStream ris = AbstractFileClient.class.getClassLoader().getResourceAsStream(CLASSPATH_CONFIG_FILENAME);
        Properties properties = new Properties();
        try {
            properties.load(ris);
        } catch (IOException e) {
            throw FileClientException.getInstance("配置文件加载失败，请将配置文件放置类路劲中");
        }
        // 环境配置
        String tmpFileEnv = properties.getProperty("active.env");
        FileEnv fileEnv = FileEnv.valueOf(tmpFileEnv);
        this.fileEnv = fileEnv;

        // ftp配置
        this.ftpId = properties.getProperty("ftp.ip");
        this.ftpPort = Integer.parseInt(properties.getProperty("ftp.port"));
        this.ftpUsername = properties.getProperty("ftp.username");
        this.ftpPassword = properties.getProperty("ftp.password");
        this.ftpRootPath = properties.getProperty("ftp.rootPath");

        // 本地配置
        this.localRootPath = properties.getProperty("local.rootPath");

        // 服务器配置
        this.serverDiskPath = properties.getProperty("server.diskPath");
        this.serverHost = properties.getProperty("server.host");
        this.serverPort = Integer.parseInt(properties.getProperty("server.port"));
        this.serverUriPath = properties.getProperty("server.uriPath");

    }

    /**
     * 处理文件名,fileName为空则会随机生成，以.(例如：.png,.jpeg)开头则会认为是后缀名，
     * 会随机生成一个文件名并拼接上后缀名，如果fileName不为空，也不以.开头，原样返回。
     *
     * @return 处理后的文件名，
     */
    protected String handleFileName(String fileName) {
        // 原样返回
        if (!StrUtil.isBlank(fileName) && !fileName.startsWith(".")) {
            return fileName;
        }

        String randomFileName = UUID.randomUUID().toString().replace("-", "");
        // 随机生成文件名
        if (StrUtil.isBlank(fileName)) {
            return randomFileName;
        }

        // 随机文件名拼接后缀
        if (fileName.startsWith(".")) {
            return String.format("%s%s", randomFileName, fileName);
        }
        return fileName;
    }

    /**
     * 处理文件路劲
     *
     * @param rootPath     根路劲
     * @param relativePath 相对路劲
     * @return
     */
    protected String handleFilePath(String rootPath, String relativePath) {
        if (StrUtil.isBlank(rootPath)) {
            return relativePath;
        }
        if (StrUtil.isBlank(relativePath)) {
            return rootPath;
        }

        if (!rootPath.endsWith(File.pathSeparator) && relativePath.startsWith(File.pathSeparator)) {
            relativePath = File.pathSeparator + relativePath;
        }

        return String.format("%s%s", rootPath, relativePath);
    }

    /**
     * 如果是服务环境，返回的是网络路劲，如果是本地环境则返回磁盘路劲
     *
     * @return 真实的路劲
     */
    protected String realResPath(String filePath, String fileName) {
        if (!StrUtil.isBlank(filePath) && filePath.endsWith("/")) {
            filePath = filePath.substring(0, filePath.length() - 1);
        }

        // 服务器环境配置
        if (fileEnv.key == FileEnv.SERVER.getKey()) {
            String serverPath = String.format("%s:%s%s", this.serverHost, this.serverPort, this.serverUriPath);

            if (serverPath.endsWith("/")) {
                serverPath = serverPath.substring(0, serverPath.length() - 1);
            }
            if (!StrUtil.isBlank(filePath)) {
                return String.format("%s/%s/%s", serverPath, filePath, fileName);
            } else {
                return String.format("%s/%s", serverPath, fileName);
            }
        }

        // 本地环境配置
        return String.format("%s/%s", this.serverDiskPath, fileName);
    }

    /**
     * 得到文件流
     *
     * @param filePath 文件路劲
     * @return FileInputStream
     */
    protected InputStream getFileStream(String filePath) {
        if (ObjectUtil.isEmpty(filePath)) {
            return null;
        }
        // 得到文件流
        InputStream fileStream;
        try {
            fileStream = new FileInputStream(FileUtil.file(filePath));
        } catch (FileNotFoundException e) {
            e.printStackTrace();
            throw new FileClientException("读取文件失败");
        }
        return fileStream;
    }

    /**
     * 得到文件流
     *
     * @param multipartFile spring 文件对象
     * @return FileInputStream
     */
    protected InputStream getFileStream(MultipartFile multipartFile) {
        if (ObjectUtil.isEmpty(multipartFile)) {
            return null;
        }
        InputStream fileStream = null;
        try {
            fileStream = multipartFile.getInputStream();
        } catch (IOException e) {
            e.printStackTrace();
            throw new FileClientException("获取文件对象失败");
        }
        return fileStream;
    }

    /**
     * 关闭文件标识符
     */
    protected void closeFd(Closeable... closeables) {
        if (ObjectUtil.isEmpty(closeables)) {
            return;
        }
        for (Closeable closeable : closeables) {
            if (!ObjectUtil.isEmpty(closeable)) {
                try {
                    closeable.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 文件环境配置枚举
     * 服务器环境: 使用nginx等应用服务器代理文件路劲, 例如: 192.168.1.211:8989/res
     * 本地环境： 本地文件访问，例如: /a/b/c
     */
    public enum FileEnv {
        SERVER(1, "SERVER", "服务器环境"),
        LOCAL(2, "LOCAL", "本地环境");

        FileEnv(int key, String value, String remark) {
            this.key = key;
            this.value = value;
            this.remark = remark;
        }

        public FileEnv getInstance(int key) {
            for (FileEnv fileEnv : FileEnv.values()) {
                if (fileEnv.key == key) {
                    return fileEnv;
                }
            }
            return null;
        }

        private int key;

        private String value;

        private String remark;

        public int getKey() {
            return key;
        }

        public String getValue() {
            return value;
        }

        public String getRemark() {
            return remark;
        }
    }

}
